<template>
  <div class="select-data-container">
    <div class="select-box" >
      <el-select
        v-model="labelValue"
        v-bind="$attrs"
        :disabled="disabled || !selectAble"
        :filterable="subType === 'select'"
        :popper-class="subType === 'select'?'':'select-tree'"
        :filter-method="searchAbel ? dataFilter : null"
        v-on="$listeners"
        contenteditable="false"
        @change="dataChange"
        @focus.prevent.stop="alertDialog"
        @blur.prevent.stop="alertDialog"
        style="display: block;"
        clearable
        ref="select"
        @remove-tag="removeTag"
        @visible-change="visibleChange"
        :allow-create="canInput"
        :default-first-option="canInput"
        onmouseover="this.title = this.getElementsByClassName('el-input__inner')[0].value"
      >
        <el-option
          v-for="o in mapSelectOptions"
          :key="o.id"
          :label="o.label"
          :value="o.value"
          :disabled="o.disabled || $attrs.multiple"
        >
          <template v-if="labelFields.length">
            <span v-for="(itm, index) in labelFields" :key="index">{{o[itm]}}</span>
          </template>
        </el-option>
      </el-select>
      <template v-if="!disabled">
        <i
          class="icon el-icon-search active-search-icon"
          v-show="searchIconVisible"
          slot="suffix"
          @click.stop="alertDialog"
        ></i>
      </template>
    </div>
    <search-dialog-type2
      :visibleValue.sync="dialogShow"
      :props="props"
      :url="url"
      :title="title"
      ref="dialog2"
      :options.sync="optionsData"
      :params="params"
      :paramsMap="paramsMap"
      :headers="headers"
      :responseType="responseType"
      :getDictResultMap="getDictResultMap"
      :getDictSuccessStatus="getDictSuccessStatus"
      :searchKey="searchKey"
      :labelFields="labelFields"
      v-bind="$attrs"
      v-on="bindListeners"
      :value="value"
      @dataChange="dataChange"
      @dialogDataChange="dialogDataChange"
    >
      <template slot="appendSearch" >
        <slot name="appendSearch" :data="params"></slot>
      </template>
    </search-dialog-type2>
  </div>
</template>

<script>
  import searchDialog from './dialog/searchDialog';
  import searchDialogType2 from './dialog/searchDialogType2';
  import personDialog from './dialog/personDialog';
  import Label from './directives/label';
  import BaseRequestComponent from "../BaseRequestComponent";
  import arr from "../../../../utils/function/arr";
export default {
  name: "ZbFormSelectData",
  extends:BaseRequestComponent,
  components: {searchDialog,personDialog,searchDialogType2},
  directives: { Label },
  filters: {},
  mixins: [],
  model: {
    prop: "value",
    event: "input"
  },
  props: {
    value:  [Object,Array,Number,String],
    filterable: Boolean,
    maxCount:null,
    url: {
      type: String,
      default: ""
    }, // 请求地址
    canInput: {
      type: Boolean,
      default: false
    }, // 是否可以输入
    selectAble: {
      type: Boolean,
      default: true
    }, // 是否可以选择
    params: {
      type: Object,
      default: () => ({
        pageNum: 1,
        pageSize: 20,
      })
    },
    paramsMap: {
      type: Object,
      default: () => ({
        pageNum: 'pageNum',
        pageSize: 'pageSize',
      })
    },
    // 弹窗的类型
    dialogType: {
      type: Number,
      default:() =>1
    },
    options: Array, // 选项
    props: {
      type: Object,
      default: () => ({
        label: "label",
        value: "value",
      })
    },
    title: {
      type: String,
      default: "数据选择"
    },
    disabled: Boolean,
    dataField: String, // 返回结果中显示的字段名
    // 弹出选则框类型 select treeSelect
    subType: {
      type: String,
      default: "select"
    },
    labelText: [String, Number, Array], // 无下拉选项时显示的名称
    // 下拉选项显示字段
    labelFields: {
      type: Array,
      default: () => []
    },
    searchAbel: Boolean, // 开启搜索
    searchKey: {
      // 查询请求的key
      default: "nameOrNumber"
    },
    searchIconVisible: {
      // 显示搜索图标
      type: Boolean,
      default: false
    },
    searchDialogEnable: {
      // 是否开启显示搜索框
      type: Boolean,
      default: true
    },
    autoFirst: {
      // 是否自动选择第一个
      type: Boolean,
      default: false
    },
    asyncLoad: {
      // 是否是同步加载数据 同步为 true（当列表有多个该组件渲染时，只会加载一次） 异步为 false
      type: Boolean,
      default: false
    },
    dynamicLableText:[String, Number, Array],
  },
  data() {
    return {
      optionsData: this.options || [],
      labelValue: "",
      dialogShow: false,
      storeMapSelectOptions:null
    };
  },
  created() {
    // 临时存储的数据
    this.storeMapSelectOptions = this.mapSelectOptions
  },
  computed: {
     bindListeners() {
      const events = this.$attrs.listeners
      return Object.assign(this.$listeners,events)
    },
    mapSelectOptions() {
      let directiveValues = null
      if (this.$vnode.data.directives && this.$vnode.data.directives.length ){
        directiveValues = this.$vnode.data.directives[0].value
      }
      const { label, value } = this.props;
      const options = this.optionsData.map(item => {
        item.label = item[label];
        item.value = item[value];
        return item;
      });
      if (this.$attrs.multiple && this.value instanceof Array) {
        let newVar = null
        let newVarLabel = null
        this.value.forEach((itm, index) => {
          if (
            options.findIndex(i => i[this.props.value] === itm) === -1 &&
            (directiveValues||this.labelText) &&
            (directiveValues||this.labelText).length > index
          ) {
            if (this.storeMapSelectOptions && this.storeMapSelectOptions.length){
              newVar = this.storeMapSelectOptions.find(i => i[value] === itm)
              newVarLabel = newVar[label]
            }
            const obj = {
              label: newVarLabel || (directiveValues||this.labelText)[index],
              value: itm
            };
            this.$set(obj, label, newVarLabel || (directiveValues||this.labelText)[index]);
            this.$set(obj, value, itm);
            options.push(obj);
          }
        });
      } else if (
        !this.$attrs.multiple &&
        options.findIndex(i => i[this.props.value] === this.value) === -1 &&
        (directiveValues||this.labelText)
      ) {
        const obj = {
          label: (directiveValues||this.labelText),
          value: this.value
        };
        this.$set(obj, label, (directiveValues||this.labelText));
        this.$set(obj, value, this.value);
        options.push(obj);
      }
      return options;
    },
  },
  watch: {
    value: {
      handler(val) {
        if (this.inOptions() || !this.createdRequest){
          this.labelValue = val
        }else{
          this.labelValue = null
        }
      },
      immediate: true
    },
    url: {
      handler(val) {
        if (val && this.subType === "select" && !this.$attrs.cascade) {
          if (this.createdRequest){
            this.getAsyncOptions();
          }
        }
      },
      immediate: true
    },
    params: {
      handler(val, oldVal) {
        if (val !== oldVal && this.subType === "select") {
          if (this.createdRequest){
            this.getAsyncOptions();
          }
        }
      },
      deep: true
    },
  },
  methods: {
    // 判断 value 是否在 数组 arr 中
    inOptions(){
      if (!this.$attrs.multiple){
        for (let i = 0; i < this.mapSelectOptions.length; i++) {
          if (this.mapSelectOptions[i].value === this.value){
            return true
          }
        }
        return false
      }
      return true
    },
    // 获取选项数据
    getAsyncOptions() {
      this.optionsData = []
      const key = encodeURIComponent(
        this.url + JSON.stringify(this.params) + this.$attrs.method
      );
      // const key = encodeURIComponent(this.url + this.params + this.$attrs.method)
      const optionsSelect = this.$zbStore.state.optionsCache.data;
      // 表示查询的是这个接口是否被请求
      const count = this.$zbStore.state.optionsCache.count;
      const index = optionsSelect.findIndex(item => item.key === key);
      if (index !== -1) {
        this.optionsData = optionsSelect[index].options;
        return;
      } else {
        if (!this.asyncLoad){
          // 异步加载
          this.getOptionsDictAsync(optionsSelect,key)
        }else{
          if (count[key] === undefined){
            return this.getOptionsDictSync(optionsSelect,key)
          }
          // 有一次请求，但是请求没有完成，就index!=-1, (count=requesting || count=undefined)
          if (count[key] ==='requesting'){
            // 会循环的取这个 optionsSelect 数据以及赋值操作，直到取出数据为止，防止发生多次渲染，多次调用接口
            setTimeout(()=>{
              this.getAsyncOptions()
            },200)
          }
          // 有一次了,请求完成了，就index!=-1, count=1
          if (count[key] ==='requested'){
            this.optionsData = optionsSelect[index].options;
            return;
          }
        }
      }
    },
    // 获得选项的字典 同步
    async getOptionsDictSync(optionsSelect,key){
      this.$zbStore.dispatch("setCatchCount", {key:key,status:'requesting'});
      return await this.getDict(this.url, this.params, this.$attrs.method).then(res => {

        let status = eval(`res.${this.getDictResultMap.status}`)
        let data = eval(`res.${this.getDictResultMap.data}`)
        let list = eval(`res.${this.getDictResultMap.list}`)
        if (status === this.getDictSuccessStatus) {
          // 是否过滤数据
          if (this.$listeners.filterData) this.$emit("filterData",res);
          if (data && list && list instanceof Array) {
            this.optionsData = list || [];
            if (this.autoFirst) {
              // 自动选择第一个
              this.labelValue = list[0][this.props.value];
              this.dataChange(list[0][this.props.value]);
              this.$emit("input", this.labelValue);
            }
          } else if (data instanceof Array && data.length) {

            this.optionsData = data || [];
            if (this.autoFirst) {
              this.labelValue = data[0][this.props.value];
              this.dataChange(data[0][this.props.value]);
              this.$emit("input", this.labelValue);
            }
          } else {
            // 防止查询条件更新后查不到数据的情况下 清空下拉列表
            this.optionsData = [];
            this.labelValue = "";
          }
          if (this.dataField) {
            this.optionsData = this.optionsData.map(
              itm => itm[this.dataField]
            );
          }
          const obj = {
            key: key,
            options: this.optionsData,
            count:0
          };
          this.$zbStore.dispatch("setCatch", obj);
          this.$zbStore.dispatch("setCatchCount", {key:key,status:'requested'});
        }
      });
    },
    // 获得选项的字典 异步
    getOptionsDictAsync(optionsSelect,key){
      return this.getDict(this.url, this.params, this.$attrs.method).then(res => {
        let status = eval(`res.${this.getDictResultMap.status}`)
        let data = eval(`res.${this.getDictResultMap.data}`)
        let list = eval(`res.${this.getDictResultMap.list}`)
        if (status === this.getDictSuccessStatus) {
          // 是否过滤数据
          if (this.$listeners.filterData) this.$emit("filterData",res);
          if (data && list && list instanceof Array) {
            this.optionsData = list || [];
            if (this.autoFirst) {
              // 自动选择第一个
              this.labelValue = list[0][this.props.value];
              this.dataChange(list[0][this.props.value]);
              this.$emit("input", this.labelValue);
            }
          } else if (data instanceof Array && data.length) {

            this.optionsData = data || [];
            if (this.autoFirst) {
              this.labelValue = data[0][this.props.value];
              this.dataChange(data[0][this.props.value]);
              this.$emit("input", this.labelValue);
            }
          } else {
            // 防止查询条件更新后查不到数据的情况下 清空下拉列表
            this.optionsData = [];
            this.labelValue = "";
          }
          if (this.dataField) {
            this.optionsData = this.optionsData.map(
              itm => itm[this.dataField]
            );
          }
          const obj = {
            key: key,
            options: this.optionsData
          };
          this.$zbStore.dispatch("setCatch", obj);
        }
      });
    },
    // 弹出选择框
    alertDialog() {
      if (!this.searchDialogEnable) return;
      if (!this.disabled) {
        this.dialogShow = true;
      }
    },
    visibleChange(e){
      this.$nextTick(function () {
        let elementsByClassName = document.getElementsByClassName("el-select-dropdown");
        if (elementsByClassName && elementsByClassName.length){
          for (let i = 0; i < elementsByClassName.length; i++) {
            elementsByClassName[i].setAttribute("style", "display:none")
          }
        }
      })
    },
    // dataChange 事件 返回选中的对象
    dataChange(val) {
      if (this.maxCount && val.length > this.maxCount){
        val.pop()
        return this.$message.info(`最多只能选择${this.maxCount}项`)
      }
      const { value } = this.props;
      if(val instanceof Array && val.length){

        const newArrayValue = val.map(ele => {
          return this.mapSelectOptions.find(i => i[value] === ele);
        });
        let newArrayLabel = this.mapSelectOptions.filter(i => val.includes(i[value]))
        newArrayLabel =  arr(newArrayLabel).pluck(this.props.label).all()

        this.$vnode.context.$emit('changeData',newArrayLabel)
        this.$emit( "labelChange",newArrayLabel);


        if (this.bindListeners.dataChange){
          this.bindListeners.dataChange(newArrayValue,val,newArrayLabel)
        }
        if (this.$listeners.dataChange && !this.bindListeners.dataChange){
          this.$emit( "dataChange",newArrayValue,val,newArrayLabel);
        }
      }else{
        let item = this.optionsData.find(i => i[value] === val)
        this.$vnode.context.$emit('changeData',item[this.props.label])
        this.$emit( "labelChange",item[this.props.label]);
        if (this.bindListeners.dataChange){
          this.bindListeners.dataChange(item,val,item[this.props.label])
        }
        if (this.$listeners.dataChange && !this.bindListeners.dataChange){
          this.$emit( "dataChange",item,val,item[this.props.label]);
        }
      }
    },
    // 移除 事件 返回选中的对象
    removeTag(val) {
      let dialog2 = this.$refs.dialog2;
      if (dialog2.disabledRow && dialog2.disabledRow.length){
        dialog2.disabledRow = dialog2.disabledRow.filter(item=>item[dialog2.props.value]!==val)
      }
      if (dialog2.checkedValuesAllObj){
        let keys = Object.keys(dialog2.checkedValuesAllObj)
        for (let i = 0; i < keys.length; i++) {
          let checkedValuesAllObjElement = dialog2.checkedValuesAllObj[keys[i]];
          if (checkedValuesAllObjElement && checkedValuesAllObjElement.length){
            dialog2.checkedValuesAllObj[keys[i]] = checkedValuesAllObjElement.filter(item=>item[dialog2.props.value]!==val)
          }
        }
      }
    },
    // change事件
    dialogDataChange(data) {
      const { value } = this.props;
      if (this.$attrs.multiple && data instanceof Array && data.length) {
        data.forEach(itm => {
          if(!this.value.includes(itm[value])) {
            this.value.push(itm[value])
          }
          if (this.optionsData.findIndex(i => i[value] === itm[value]) === -1) {
            this.optionsData.push(itm);
          }
        });
        this.dataChange(this.value)
      } else {
        if (this.optionsData.findIndex(i => i[value] === data[value]) === -1) {
          this.optionsData.push(data);
        }
        this.labelValue = data[value]
        this.dataChange(this.labelValue)
      }
    },
    // 搜索数据
    dataFilter(val) {
      this.$set(this.params, this.searchKey, val);
      this.getAsyncOptions();
    }
  }
};
</script>

<style scoped lang="scss">
  .active-search-icon{
    color: #1890ff !important;
    font-weight: bold;
  }
  .active-search-icon :hover{
    color: #1890ff22 !important;
    font-weight: bold;
  }
.select-data-container {
  position: relative;
  /deep/ .el-input {
    &:hover {
      cursor: pointer;
    }
    input {
      &:hover {
        cursor: pointer;
      }
    }
  }
  .select-box {
    position: relative;
    .icon {
      cursor: pointer;
      color: #c0c4cc;
      position: absolute;
      right: 10px;
      top: 50%;
      transform: translateY(-50%);
    }
  }
  /deep/ .el-select {
    width: 100%;
    height: 100%;
    display: block;
    position: relative;
    .el-input__suffix {
      display: none;
      .el-icon-arrow-up {
        display: none;
      }
    }
    &:hover .el-input__suffix {
      display: inline;
      margin-right: 16px;
    }
  }
  /deep/ .is-disabled .el-input__inner {
    color: #4d4d4d;
  }


}
.select-tree {
  display: none;
}
  ::v-deep.el-select-dropdown__list{
    display: none !important;
  }
  >>> .el-select-dropdown__list {
    display: none !important;
  }
</style>
